<?php
/**
 * Here is your custom functions.
 */

use support\Cache;

if (!function_exists('parse_name')) {
    /**
     * 字符串命名风格转换
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
     * @param string $name 字符串
     * @param int $type 转换类型
     * @param bool $ucfirst 首字母是否大写（驼峰规则）
     * @return string
     */
    function parse_name(string $name, int $type = 0, bool $ucfirst = true): string
    {
        if ($type) {
            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                return strtoupper($match[1]);
            }, $name);

            return $ucfirst ? ucfirst($name) : lcfirst($name);
        }

        return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $name), '_'));
    }
}

if (!function_exists('cache')) {
    /**
     * 设置缓存
     * @param $key
     * @param string $value
     * @param null $expires 过期时间
     * @return bool|mixed
     */
    function cache($key, $value = "", $expires = null)
    {
        if (empty($value)) {
            $cache = Cache::get($key);
        } else {
            if (empty($expires)) {
                $cache = Cache::set($key, $value);
            } else {
                $cache = Cache::set($key, $value, $expires);
            }
        }
        return $cache;
    }
}

if (!function_exists('parse_name')) {
    /**
     * 获取controller
     * @param $controller
     * @return mixed
     */
    function get_controller($controller)
    {
        $controller_data = explode("\\", $controller);
        $url = $controller_data[3];
        return $url ?? "";
    }
}


if (!function_exists('create_file_auto')) {
    /**
     * 文件创建
     * @param $controller --类名
     * @param $action --方法名
     */

    function create_file_auto($controller, $action)
    {
        $apiRoutePath = app_path() . '/api/controller/' . $controller . '.php';
        if (!file_exists($apiRoutePath)) {
            fopen($apiRoutePath, "w");
            $connet = <<<EOF
<?php

namespace app\api\controller;

class $controller extends Base
{

    public function $action()
    {
         return \$this->buildSuccess();
    }
}

EOF;
            file_put_contents($apiRoutePath, $connet, FILE_APPEND);
        }
        //$seach = implode("/",[$controller,$action]);
        //$AdminList  = new \app\model\AdminList();
        //$AdminList->where('api_class',$seach)->field('id,api_class')->select();

    }


}


/**
 * 生成uid
 * @param string $prefix
 * @return string
 */
function create_uuid($prefix = "")
{
    $str = md5(uniqid(mt_rand(), true));
    $uuid = substr($str, 0, 8) . '-';
    $uuid .= substr($str, 8, 4) . '-';
    $uuid .= substr($str, 12, 4) . '-';
    $uuid .= substr($str, 16, 4) . '-';
    $uuid .= substr($str, 20, 12);
    return $prefix . $uuid;
}


/**
 * 批量请求
 * @param array $request_buffer_array ['ip:port'=>req_buf, 'ip:port'=>req_buf, ...]
 * @return multitype:unknown string
 */
function multiRequest($request_buffer_array)
{
    $lastSuccessIpArray = array();
    $client_array = $sock_to_ip = $ip_list = array();
    foreach ($request_buffer_array as $address => $buffer) {
        list($ip, $port) = explode(':', $address);
        $ip_list[$ip] = $ip;
        $client = stream_socket_client("tcp://$address", $errno, $errmsg, 1);
        if (!$client) {
            continue;
        }
        $client_array[$address] = $client;
        stream_set_timeout($client_array[$address], 0, 100000);
        fwrite($client_array[$address], $buffer);
        stream_set_blocking($client_array[$address], 0);
        $sock_to_address[(int)$client] = $address;
    }
    $read = $client_array;
    $write = $except = $read_buffer = array();
    $time_start = microtime(true);
    $timeout = 0.99;
    // 轮询处理数据
    while (count($read) > 0) {
        if (@stream_select($read, $write, $except, 0, 200000)) {
            foreach ($read as $socket) {
                $address = $sock_to_address[(int)$socket];
                $buf = fread($socket, 8192);
                if (!$buf) {
                    if (feof($socket)) {
                        unset($client_array[$address]);
                    }
                    continue;
                }
                if (!isset($read_buffer[$address])) {
                    $read_buffer[$address] = $buf;
                } else {
                    $read_buffer[$address] .= $buf;
                }
                // 数据接收完毕
                if (($len = strlen($read_buffer[$address])) && $read_buffer[$address][$len - 1] === "\n") {
                    unset($client_array[$address]);
                }
            }
        }
        // 超时了
        if (microtime(true) - $time_start > $timeout) {
            break;
        }
        $read = $client_array;
    }

    foreach ($read_buffer as $address => $buf) {
        list($ip, $port) = explode(':', $address);
        $lastSuccessIpArray[$ip] = $ip;
    }
    $lastFailedIpArray = array_diff($ip_list, $lastSuccessIpArray);
    ksort($read_buffer);
    return $read_buffer;
}


function formatSt($str, $date, &$code_map)
{
    // time:[suc_count:xx,suc_cost_time:xx,fail_count:xx,fail_cost_time:xx]
    $st_data = $code_map = array();
    $st_explode = explode("\n", $str);
    // 汇总计算
    foreach($st_explode as $line)
    {
        // line = IP time suc_count suc_cost_time fail_count fail_cost_time code_json
        $line_data = explode("\t", $line);
        if(!isset($line_data[5]))
        {
            continue;
        }
        $time_line = $line_data[1];
        $time_line = ceil($time_line/300)*300;
        $suc_count = $line_data[2];
        $suc_cost_time = $line_data[3];
        $fail_count = $line_data[4];
        $fail_cost_time = $line_data[5];
        $tmp_code_map = json_decode($line_data[6], true);
        if(!isset($st_data[$time_line]))
        {
            $st_data[$time_line] = array('suc_count'=>0, 'suc_cost_time'=>0, 'fail_count'=>0, 'fail_cost_time'=>0);
        }
        $st_data[$time_line]['suc_count'] += $suc_count;
        $st_data[$time_line]['suc_cost_time'] += $suc_cost_time;
        $st_data[$time_line]['fail_count'] += $fail_count;
        $st_data[$time_line]['fail_cost_time'] += $fail_cost_time;

        if(is_array($tmp_code_map))
        {
            foreach($tmp_code_map as $code=>$count)
            {
                if(!isset($code_map[$code]))
                {
                    $code_map[$code] = 0;
                }
                $code_map[$code] += $count;
            }
        }
    }
    // 按照时间排序
    ksort($st_data);
    // time => [total_count:xx,suc_count:xx,suc_avg_time:xx,fail_count:xx,fail_avg_time:xx,percent:xx]
    $data = array();
    // 计算成功率 耗时
    foreach($st_data as $time_line=>$item)
    {
        $data[$time_line] = array(
            'time'          => date('Y-m-d H:i:s', $time_line),
            'total_count'   => $item['suc_count']+$item['fail_count'],
            'total_avg_time'=> $item['suc_count']+$item['fail_count'] == 0 ? 0 : number_format(($item['suc_cost_time']+$item['fail_cost_time'])/($item['suc_count']+$item['fail_count']), 6),
            'suc_count'     => $item['suc_count'],
            'suc_avg_time'  => $item['suc_count'] == 0 ? $item['suc_count'] : number_format($item['suc_cost_time']/$item['suc_count'], 6),
            'fail_count'    => $item['fail_count'],
            'fail_avg_time' => $item['fail_count'] == 0 ? 0 : number_format($item['fail_cost_time']/$item['fail_count'], 6),
            'precent'       => $item['suc_count']+$item['fail_count'] == 0 ? 0 : number_format(($item['suc_count']*100/($item['suc_count']+$item['fail_count'])), 4),
        );
    }
    $time_point =  strtotime($date);
    for($i=0;$i<288;$i++)
    {
        $data[$time_point] = isset($data[$time_point]) ? $data[$time_point] :
            array(
                'time' => date('Y-m-d H:i:s', $time_point),
                'total_count'   => 0,
                'total_avg_time'=> 0,
                'suc_count'     => 0,
                'suc_avg_time'  => 0,
                'fail_count'    => 0,
                'fail_avg_time' => 0,
                'precent'       => 0,
            );
        $time_point +=300;
    }
    ksort($data);
    return $data;
}

/**
 * 对传入的参数进行XSS过滤
 * @param array $data
 * @return array
 */
function filter(array $data): array
{
    array_walk_recursive($data, function (&$value) {
        // 处理NULL 数据,Null 转为空字符串
        if ($value === null) {
            $value = '';
        }
        //不对magic_quotes_gpc转义过的字符使用addslashes(),避免双重转义。
        if (!get_magic_quotes_gpc()) {
            //给单引号（'）、双引号（"）、反斜线（\）与 NUL（NULL 字符）加上反斜线转义
            $value = addslashes($value);
        }
        $value = htmlspecialchars($value, ENT_QUOTES);
    });
    return $data;
}


/**
 * 处理响应，根据请求类型执行不同响应
 *
 * @author HSK
 * @date 2021-11-18 13:55:45
 *
 * @param integer $code
 * @param string $msg
 * @param array $data
 *
 * @return \Webman\Http\Response
 */
function handle_response($data = [], $code = 200, $msg = 'success')
{
    // API响应
    if (request()->expectsJson()) {
        return api($data, $code, $msg);
    }
    // 视图响应
    else {
        $controller = request()->controller;
        $controller = substr($controller, strpos($controller, 'controller\\') + 11);
        $controller = parse_name($controller);
        $action     = request()->action;
        $action     = parse_name($action);

        return view($controller . '/' . $action, $data);
    }
}

/**
 * API响应
 *
 * @author HSK
 * @date 2021-11-18 10:40:39
 *
 * @param array $data
 * @param integer $code
 * @param string $msg
 *
 * @return \Webman\Http\Response
 */
function api($data = [], $code = 200, $msg = 'success')
{
    return json([
        'code' => $code,
        'msg'  => $msg,
        'data' => $data,
    ], 320);
}

/**
 * 生成URL，带有参数
 *
 * @author HSK
 * @date 2021-11-17 16:22:55
 *
 * @param string $name
 * @param array $parameters
 *
 * @return string
 */
function url($name, $parameters = []): string
{
    $route = route($name);
    if (!$route) {
        return '';
    }

    if (!empty($parameters)) {
        return $route . '?' . http_build_query($parameters);
    }

    return $route;
}

/**
 * 字符串命名风格转换
 *
 * @author HSK
 * @date 2021-08-22 16:37:40
 *
 * @param string $name
 * @param integer $type
 * @param boolean $ucfirst
 *
 * @return string
 */
function parse_name(string $name, int $type = 0, bool $ucfirst = true): string
{
    if ($type) {
        $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
            return strtoupper($match[1]);
        }, $name);

        return $ucfirst ? ucfirst($name) : lcfirst($name);
    }

    return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
}

/**
 * 设置token
 * @param $appId
 * @param $appKey
 * @param $preStr
 * @param int $user_id
 * @return string
 */
function setJwtToken($appId,$appKey,$preStr, $user_id = 1551)
{
    /**
     * composer require firebase/php-jwt
     * iss: jwt签发者
     * sub: jwt所面向的用户
     * aud: 接收jwt的一方
     * exp: jwt的过期时间，这个过期时间必须要大于签发时间
     * nbf: 定义在什么时间之前，该jwt都是不可用的.
     * iat: jwt的签发时间
     * jti: jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击。
     */
    $appUrl = "www.hao123.com";
    $key = md5(sha1($appKey));//自定义秘钥，加密解密都需要用到
    $time = time(); //当前时间
    $token = [
        'iss' => 'www.baidu.com',
        'aud' => 'www.hao123.com',
        'iat' => $time, //签发时间
        'nbf' => $time + 30, //(Not Before)：某个时间点后才能访问，比如设置time+30，表示当前时间30秒后才能使用
        'exp' => $time + 3600,
        'jti' => $key,
        'data' => [
            'user_id' => $user_id,
            'url' => $appUrl,
            'appId' => $appId,
            'appKey' => $appKey,
            'preStr' => $preStr,
        ]];
    $jwtToken = \Firebase\JWT\JWT::encode($token, $key);
    \support\Redis::setEx('jwt_token', 5, $jwtToken);
    return $jwtToken;
}


function getJwtToken($token,$appKey)
{
    $key = md5(sha1($appKey));//自定义秘钥，加密解密都需要用到
    try {
        $jwtToken = \Firebase\JWT\JWT::decode($token, $key, ['HS256']);
        return json(['code' => 1000, 'data' => $jwtToken, 'msg' => '获取成功']);
    } catch (\Firebase\JWT\SignatureInvalidException $e) {
        return json(['code' => 1001, 'data' => $e->getMessage(), 'msg' => '签名不正确']);
    } catch (\Firebase\JWT\BeforeValidException $e) {
        return json(['code' => 1001, 'data' => $e->getMessage(), 'msg' => '签名在某个时间点之后才能用']);
    } catch (\Firebase\JWT\ExpiredException $e) {
        return json(['code' => 1001, 'data' => $e->getMessage(), 'msg' => 'token过期']);
    } catch (\Exception $e) {  //其他错误
        return json(['code' => 1001, 'data' => $e->getMessage(), 'msg' => '获取成功']);
    }
}
